package com.dyna.patterns.creation.singleton;

public class Person {

//    private static Person instance;
    /** 内存可见性 */
    private volatile static Person instance;

    /**
     * 1. 私有方法保证外部不能实例化
     */
    private Person() {

    }

    //2. 外部只能通过从这个类中获取，那么就要提供一个方法让外面能够从这个类中获取到
//    锁粒度太大
//    public static synchronized Person getPerson() {
//        if (instance == null) {
//            instance = new Person();
//        }
//        return instance;
//    }

//    public static synchronized Person getPerson() {
//        //两个方法同时进来抢这把锁，这样效率还是很低
//        synchronized (Person.class) {
//            if (instance == null) {
//                instance = new Person();
//            }
//        }
//        return instance;
//    }

//    public static synchronized Person getPerson() {
//        //先判空再加锁，这样还是会导致多线程问题。那么就此引出了双重检查锁
//        if (instance == null) {
//            synchronized (Person.class) {
//                instance = new Person();
//            }
//        }
//        return instance;
//    }

    public static synchronized Person getPerson() {
        //第一层判空是为了加锁
        if (instance == null) {
            synchronized (Person.class) {
                //第二层判空是为了效率更高。当第二个线程进来时，发现instance已经不为空了，那么就直接释放锁了。这样效率就更高了。
                if (instance == null) {
                    //创建对象在内存中分为三步。创建对象，分配内存，指向引用。多线程情况下可能会导致顺序出问题。那么就需要加个内存可见性。
                    instance = new Person();
                }
            }
        }

        return instance;
    }

    /**
     * 在getPerson中如果有十个线程进来同时判断为空，那么还是会创建十次。
     * 解决办法就是加锁，第一就是在方法上加锁，在调用这个方法的时候直接把方法锁住，这样就能防止其他地方调用这个方法。
     *      但是这样做弊端是什么呢?锁的粒度太大了，也就是锁的范围太大了。
     * 方法二：将创建内容放在同步代码块中
     */

}
